var globalDebug = true;
function toolTemplate(option) {
    this.name = 'tool';
    this.text = '新插件';
    this.pannel = '';
    this.ico = undefined;
    this.class = 'tool';
    this.click = function (e) {
    };
    this.callback = undefined;
    this.create = function () {
        var button = $('<button type="button"></button>').click(function (e) {
            var name = $(this).attr('name');
            LC.S.tools[name].click(e);
        });
        button.attr('name', this.name).text(this.text);
        if (this.ico != undefined) {
            button.prepend($('<span></span>').addClass(this.ico))
        }
        return button;
    }
    $.extend(this, option);
}
var longService = function (url) {
    this.serviceUrl = url;
    /**主面板**/
    this.PANNEL_MAIN = '#main';
    /**查询面板**/
    this.PANNEL_QUERY = '.pannelQuery';
    /**详情面板**/
    this.PANNEL_DETAIL = '#main';
    /**添加面板**/
    this.PANNEL_ADD = '.pannelAdd';
    this.page = {
        /**分页容器**/
        PANNEL: '.pannelPage',
        url: this.serviceUrl,
        /**总页数**/
        count: 0,
        /**页号**/
        index: 1,
        /**页记录数**/
        size: 10,
        /**总记录数**/
        sum: 0,
        /**表单数据**/
        formData: [],
        fillForm: function () {
        },
        /**查询**/
        query: function (data) {
            if (data != undefined) {
                this.formData = data;
            }
            var subData = [].concat(this.formData,
                [{name: 'page.index', value: this.index},
                    {name: 'page.size', value: this.size}]
            );
            var pannel = this.PANNEL;
            $.ajax({
                url: this.url,
                data: subData,
                dataType: "html",
                success: function (rs) {
                    $(pannel).fadeOut('slow', function () {
                        $(pannel).slideDown('slow');
                        $(pannel).html(rs);
                    });
                }
            });
        },
        /**跳转首页**/
        goFirst: function () {
            if (this.index > 1) {
                this.index = 1;
                this.query();
            }
        },
        /**向前翻页**/
        goPrev: function () {
            if (this.index > 1) {
                this.index--;
                this.query();
            }
        },
        /**向后翻页**/
        goNext: function () {
            if (this.index < this.count) {
                this.index++;
                this.query();
            }
        },
        /**跳转尾页**/
        goEnd: function () {
            if (this.index < this.count) {
                this.index = this.count;
                this.query();
            }
        },
        /**
         * 跳转指定页
         * @param index 页号（index >= 1）
         */
        go: function (index) {
            if (index != this.index) {
                this.index = index;
                this.query();
            }
        },
        /**
         * 变更页面显示的记录数
         * @param size 页面记录数（size > 0）
         */
        changeSize: function (size) {
            if (this.size != size) {
                this.size = size;
                this.query();
            }
        }
    }
    this.add = function (data, callback) {
        data.push({name: longController.const.ACT, value: longController.const.ADD});
        LC.goPage(LC.S.serviceUrl, LC.S.PANNEL_MAIN, data, callback)
    }
    /**查询**/
    this.query = function () {
        //if (checkForm($(this.PANNEL_QUERY).find('*[name]'))) {
        var data = LC.serializeArray($(this.PANNEL_QUERY).find('*[name]'));
        this.page.query(data);
        //}
    }
    /**查看详情（编辑）**/
    this.detail = function (id, callback) {
        LC.goPage(LC.S.serviceUrl, LC.S.PANNEL_DETAIL, [
            {name: longController.const.ACT, value: longController.const.DETAIL},
            {name: 'id', value: id}
        ], callback);
    }
    /**保存**/
    this.save = function (callback) {
        if (checkForm($(LC.S.PANNEL_ADD).find('*[name]'))) {
            var data = LC.serializeArray($(LC.S.PANNEL_ADD).find('*[name]'));
            data.push({name: longController.const.ACT, value: longController.const.ADD},
                {name: longController.const.TYPE, value: longController.const.SAVE});
            $.getJSON(LC.S.serviceUrl, data, function (rs) {
                if (rs.code == code.SUCCESS || rs.code == code.FINISH) {
                    if (callback != undefined) {
                        callback(rs);
                    } else {
                        LC.goPage(LC.S.serviceUrl, LC.S.PANNEL_DETAIL, [{
                            name: longController.const.ACT,
                            value: longController.const.DETAIL
                        }, {name: 'id', value: rs.id}]);
                    }
                } else {
                    alert('code:' + rs.code + '\n' + msg[rs.code]);
                }
            });
        }
    }
    /**删除**/
    this.remove = function (data, callback) {
        data.push({name: longController.const.ACT, value: longController.const.REMOVE});
        $.getJSON(LC.S.serviceUrl, data, function (rs) {
            if (rs.code == code.SUCCESS || rs.code == code.FINISH) {
                if (callback == undefined) {
                    LC.fleshPage();
                } else {
                    callback(rs);
                }
            } else {
                alert(msg[rs.code]);
            }
        });
    }
    /**工具**/
    this.tools = {
        /**新建**/
        toolNew: new toolTemplate({
            name: 'toolNew',
            text: '新建',
            ico: 'icon-plus',
            class: 'toolNew',
            url: this.serviceUrl,
            click: function (e) {
                LC.S.add([], this.callback);
            }
        }),
        /**详情(编辑)**/
        toolDetail: new toolTemplate({
            name: 'toolDetail',
            text: '查看',
            ico: 'icon-libreoffice',
            class: 'toolDetail',
            url: this.serviceUrl,
            click: function (e) {
                var idcb = $(LC.S.page.PANNEL).find('input[name=id]:checked');
                if (idcb.length == 0) {
                    alert('请选择要查看的记录！');
                } else if (idcb.length > 1) {
                    alert('一次只能选择一个！');
                } else {
                    LC.S.detail(idcb.val(), this.callback);
                }
            }
        }),
        /**删除**/
        toolRemove: new toolTemplate({
            name: 'toolRemove',
            text: '删除',
            ico: 'icon-remove2',
            class: 'toolRemove',
            url: this.serviceUrl,
            click: function (e) {
                var gid = LC.serializeArray($(LC.S.page.PANNEL).find('input[name=id]:checked'));
                if (gid.length == 0) {
                    alert('请至少选择一个要删除的记录');
                    return;
                }
                if (!confirm('确定要删除所选记录吗？')) {
                    return;
                }
                LC.S.remove(gid, this.callback);
            }
        }),
        /**保存**/
        toolSave: new toolTemplate({
            name: 'toolSave',
            text: '保存',
            ico: 'icon-edit',
            class: 'toolSave',
            callback: function (rs) {
                //alert('保存成功');
                LC.goPage(LC.S.serviceUrl, LC.S.PANNEL_DETAIL, [
                    {name: longController.const.ACT, value: longController.const.DETAIL},
                    {name: 'id', value: rs.id}]);
            },
            click: function (e) {
                LC.S.save(this.callback);
            }
        }),
        /**保存并新建**/
        toolSaveNew: new toolTemplate({
            name: 'toolSaveNew',
            text: '保存并新建',
            ico: 'icon-plus',
            class: 'toolSaveNew',
            callback: function () {
                LC.S.tools.toolNew.click();
            },
            click: function (e) {
                LC.S.save(this.callback);
            }
        }),
        /**保存并关闭**/
        toolSaveClose: new toolTemplate({
            name: 'toolSaveClose',
            text: '保存并关闭',
            ico: 'icon-checkmark',
            class: 'toolSaveClose',
            callback: function () {
                LC.S.tools.toolCannel.click()
            },
            click: function (e) {
                LC.S.save(this.callback);
            }
        }),
        /**取消**/
        toolCannel: new toolTemplate({
            name: 'toolCannel',
            text: '取消',
            ico: 'icon-close',
            class: 'toolCannel',
            url: this.serviceUrl,
            click: function (e) {
                LC.goPage(this.url, LC.S.PANNEL_MAIN, null, this.callback)
            }
        }),
        /**取消**/
        toolFlesh: new toolTemplate({
            name: 'toolFlesh',
            text: '刷新',
            ico: 'icon-spinner5',
            class: 'toolFlesh',
            url: this.serviceUrl,
            click: function (e) {
                LC.fleshPage()
            }
        })
    }
    this.fillQueryForm = function () {
        var formData = this.page.formData;
        for (var i = 0; i < formData.length; i++) {
            var data = formData[i];
            $(this.PANNEL_QUERY).find('input[name=' + data.name + ']').val(data.value);
        }
    }
}
longService.prototype.edit = function (obj, url, id) {
    this.password = function (element) {
        bindInput(element, $('<input type="password" />'), this.save)
    }
    this.text = function (element) {
        var input = copyAttr(element, $('<input type="text" />'));
        var text = $(element).text();
        if (text != '点击编辑')
            $(input).val(text);
        bindInput(element, input, this.save);
    }
    this.number = function (element) {
        var text = $(element).text();
        var input = copyAttr(element, $('<input type="number" />'));
        if (text != '点击编辑')
            $(input).val(text);
        bindInput(element, input, this.save);
    }
    this.select = function (element) {
        var input = copyAttr(element, $('<select><option value="">资源加载中。。。</option></select>'));
        $.ajax({
            url: $(_this).attr('src'), beforeSend: function () {
            }, success: function (rs, s, q) {
                $(input).html(rs);
                var ops = $(input).children();
                for (var i = 0; i < ops.length; i++) {
                    if ($(ops).eq(i).text() == $(_this).text())
                        $(ops).eq(i).attr('selected', true);
                }
            }
        });
        bindInput(element, input, this.save);
    }
    this.textarea = function (element) {
        var text = $(element).text();
        var input = copyAttr(element, $('<textarea>' + text + '</textarea>'));
        bindInput(element, input, this.save)
    }
    var _this = this;
    var e = $('<span class="icon-edit"></span>');
    e.click(function (e) {
        $(this).prev().trigger('click');
    });
    $(obj).after(e);
    $(obj).click(function (e) {
        var type = $(this).attr('type');
        _this[type](this);
    });
    var copyAttr = function (element, input) {
        var attrs = element.attributes;
        for (var i = 0; i < attrs.length; i++) {
            var attr = attrs[i];
            if (LC.regexValidate(/^l_.+/, attr.name)) {
                $(input).attr(attr.name.substr(2), attr.value);
            }
        }
        return input;
    }
    var bindInput = this.bindInput = function (element, input, save) {
        $(input).blur(function (e) {
            var _this = this;

            function cancel() {
                $(_this).hide();
                $(_this).prev().toggle('slow');
                $(_this).remove();
                return;
            }

            if (($(_this).prev().attr('nullable') == undefined && $(_this).val() == '') || $(_this).val() == $(_this).prev().text()) {
                cancel();
                return;
            }
            if ($(_this).is('select') && $(_this).children(':selected').text() == $(_this).prev().text()) {
                cancel();
                return;
            }
            if (!confirm('确定保存修改吗？')) {
                cancel();
                return;
            }
            var name = $(_this).prev().attr('name');
            var regx = '/^' + $(_this).prev().attr('regx') + '$/';
            var value = $(_this).val();
            var updateId = $(_this).prev().attr('updateId');
            if (updateId != undefined) {
                id = updateId;
            }
            var type = $(_this).prev().attr('type');
            var warm = $(_this).prev().attr('warm');
            if (warm == undefined)
                warm = '该值不合适';
            if (!($(_this).prev().attr('nullable') != undefined && $(_this).val() == '') && !checkValue(regx, value, type)) {
                alert(warm);
                $(_this).focus();
                return false;
            }
            if ($(_this).prev().attr('md5') != undefined)
                value = md5(value);
            $.getJSON(url, [
                    {name: longController.const.ACT, value: longController.const.UPDATE},
                    {name: LC.const.UPDATE_ID, value: LC.S.id},
                    {name: LC.const.UPDATE_NAME, value: name},
                    {name: LC.const.UPDATE_VALUE, value: value}
                ],
                function (rs) {
                    if (rs.code == code.FINISH || rs.code == code.SUCCESS) {
                        switch ($(_this).prev().attr('type')) {
                            case 'text':
                                $(_this).prev().text(value);
                                break;
                            case 'password':
                                break;
                            case 'select':
                                $(_this).prev().text($(_this).children('[value=' + value + ']').text());
                                break;
                            case 'textarea':
                                $(_this).prev().text(value);
                        }
                        $(_this).hide();
                        $(_this).prev().toggle('slow');
                        $(_this).remove();
                    } else {
                        alert(rs.msg);
                    }
                });
        });
        $(input).keyup(function (e) {
            if (e.which == 27) {
                $(this).hide();
                $(this).prev().toggle('slow');
                $(this).remove();
                return;
            } else if (e.which == 13) {
                $(this).trigger('blur');
            }
        });
        $(input).hide();
        $(element).hide();
        $(element).after(input);
        $(input).toggle('slow');
        $(input).focus();
    }
}
var longController = function () {
}
/**服务列表**/
longController.services = new Array();
/**模块唯一标识**/
longController.key = '';
/**当前服务**/
longController.S;
/**工具栏面板**/
longController.pannelToolbar = '.toolbar';
/**切换模块服务**/
longController.attach = function (key, service) {
    if (this.S != undefined) {
        this.services[this.key] = this.S;
    }
    this.key = key;
    if (this.services[key] == undefined) {
        this.services[this.key] = service;
    }
    this.S = this.services[this.key];
}
longController.setPage = function (page) {
    $.extend(this.S.page, page);
}
longController.const = {
    ACT: '_act',
    TYPE: '_type',
    ADD: 'add',
    SAVE: 'save',
    LIST: 'list',
    DETAIL: 'detail',
    UPDATE: 'update',
    REMOVE: 'remove',
    UPDATE_ID: 'update.id',
    UPDATE_NAME: 'update.name',
    UPDATE_VALUE: 'update.value'
};
longController.goPageUrl = '';
longController.goPagePannel = '';
longController.goPageData;
/**局部页面跳转**/
longController.goPage = function (url, pannel, data, callback) {
    this.goPageUrl = url;
    this.goPagePannel = pannel;
    this.goPageData = data;
    var _this = this;
    $.ajax({
        url: url,
        data: data,
        success: function (rs) {
            $(pannel).slideUp('fast', function () {
                $(pannel).slideDown('fast');
                $(pannel).html(rs);
                _this.initControl();
                if (callback != undefined) {
                    callback(rs);
                }
            });
        }
    });
}
/**局部页面刷新**/
longController.fleshPage = function () {
    this.goPage(this.goPageUrl, this.goPagePannel, this.goPageData);
}
/**初始化公众组件**/
longController.initControl = function () {
    $('.tooltip').tooltip();
    $('select.selectmenu').selectmenu({
        change: function (event, ui) {
            $(this).trigger('change');
        }
    });
}
/**初始化工具栏**/
longController.initToolbar = function (tools) {
    if (tools == undefined) {
        tools = this.S.tools;
    }
    $(this.pannelToolbar).html('');
    for (var tool in tools) {
        $(this.pannelToolbar).append(tools[tool].create());
    }
    if ($(this.pannelToolbar).children().length == 0) {
        $(this.pannelToolbar).hide();
    } else {
        $(this.pannelToolbar).show();
    }
}
/**多选框反选**/
longController.cbAnti = function (cbs) {
    $(cbs).each(function (index, element) {
        this.checked = !this.checked
    })
}
/**全选/取消**/
longController.cbchange = function (_this, cbs) {
    $(cbs).each(function (index, element) {
        this.checked = _this.checked
    })
}
/**
 * 序列化元素,此方法返回的是JSON对象而非JSON字符串。需要使用插件或者第三方库进行字符串化操作。
 * 返回的JSON对象是由一个对象数组组成的，其中每个对象包含一个或两个名值对——name参数和value参数（如果value不为空的话）。举例来说：
 * [
 * {name: 'firstname', value: 'Hello'},
 * {name: 'lastname', value: 'World'},
 * {name: 'alias'}
 * ]
 * @param inputs
 * @param d 原数据
 * @returns {Array}
 */
var serializeArray = longController.serializeArray = function (inputs, d) {
    var data = [];
    var json = false;
    if (d != undefined)
        data = d;
    $(inputs).each(function (index, element) {
        var name = $(this).attr('name');
        var value = $(this).val();
        if (name == null)
            return;
        if ($(this).is('input[md5]'))
            value = md5(value);
        var type = $(this).attr('type');
        if (type == 'radio' && !$(this).is(':checked'))
            return;
        var tmp = {};
        if (type == 'checkbox') {
            if ($(this).is(':checked')) {
                data.push({name: name, value: value});
            }
        } else {
            data.push({name: name, value: value});
        }
    });
    return data;
}
/**
 * 将序列化的JSON数组对象转换为JSON对象
 * @param data
 * @returns {{}}
 */
longController.arrayToJson = function (data) {
    var newdata = {};
    for (var i = 0; i < data.length; i++) {
        if (newdata[data[i].name] == undefined) {
            newdata[data[i].name] = data[i].value;
        } else {
            if (typeof(newdata[data[i].name]) != 'object') {
                var tv = newdata[data[i].name];
                newdata[data[i].name] = [];
                newdata[data[i].name].push(tv);
            }
            newdata[data[i].name].push(data[i].value);
        }
    }
    return newdata;
}
longController.regexValidate = function (regex, value) {
    return regex.exec(value) != null;
}
window.LS = longService;
window.LC = longController;
function checkVersion() {
    if ($('#version').length > 0) {
        document.writeln('<h1>浏览器内核版本低于IE7</h1>');
        alert('您的浏览器版本过低，请自觉离开！\n谢谢合作！');
        return false;
    }
    if (document.documentMode == 7) {
        alert('您的浏览已经开启兼容性视图，为更好的体验请您取消兼容模式！');
        return false;
    }
    return true;
}
function checkClient() {
    if (navigator.userAgent.indexOf('Mobile') != -1) {
        $('head').append('<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />');
    } else {
    }
}
function dialog(obj, option) {
    try {
        $(obj).dialog().each(function (index, element) {
            $(this).dialog('destroy');
        })
    } catch (e) {
    }
    $(obj).dialog(option);
}
jQuery.fn.extend({
    middle: function (_this) {
        var h = Math.floor((this.parent().height() - this.outerHeight()) / 2);
        this.css('margin', h + 'px auto');
    }
});
function checkForm(inputs) {
    var chrs = true;
    for (var i = 0; i < inputs.length; i++) {
        var _this = inputs[i];
        var regx = '/' + $(_this).attr('regx') + '/';
        var value = $(_this).val();
        var type = $(_this).attr('type');
        var nullable = $(_this).attr('nullable');
        if (nullable != undefined && value == '')
            continue;
        if (type == undefined)
            type = $(_this).prop("tagName");
        var warm = $(_this).attr('warm');
        if (warm == undefined)
            warm = '该值不合适';
        if (type == 'checkbox') {
            continue;
        } else if (type == 'radio') {
            if ($(inputs).filter('[name=' + $(_this).attr('name') + ']:checked').length <= 0) {
                alert(warm);
                $(_this).focus();
                return false;
            }
        } else if (!checkValue(regx, value, type)) {
            if (globalDebug) {
                alert(warm + '\nname=' + $(_this).attr('name') + '\nregx=' + regx + '\nvalue=' + value + '\ntype=' + type + '\nnullable=' + nullable)
            } else {
                alert(warm);
            }
            $(_this).focus();
            return false;
        }
    }
    return true;
}
function checkValue(regxstr, value, type) {
    var chrs = false;
    var regx = eval(regxstr);
    switch (type.toLowerCase()) {
        case 'password':
            chrs = value != null && value != '';
            break;
        case 'text':
            if (regxstr == '/undefined/')
                chrs = value != null && value != '';
            else
                chrs = regx.exec(value) != null;
            break;
        case 'number':
            if (regxstr == '/undefined/')
                chrs = value != null && value != '';
            else
                chrs = regx.exec(value) != null;
            break;
        case 'hidden':
            if (regxstr == '/undefined/')
                chrs = value != null && value != '';
            else
                chrs = regx.exec(value) != null;
            break;
        case 'select':
            chrs = value != null && value != '';
            break;
        case 'textarea':
            chrs = value != null && value != '';
            break;
        case 'file':
            if (regxstr == '/undefined/')
                chrs = value != null && value != '';
            else
                chrs = regx.exec(value.toString()) != null;
            break;
        default:
    }
    return chrs;
}
function setCalendar(obj, format) {
    Calendar.setup({
        inputField: obj,
        trigger: obj,
        onSelect: function () {
            this.hide()
        },
        showTime: 24,
        dateFormat: format
    });
}
$.ajaxSetup({
    cache: false,
    contentType: "application/x-www-form-urlencoded;charset=utf-8",
    beforeSend: function () {
        $("#loading").dialog('open');
    },
    complete: function () {
        $("#loading").dialog('close');
    },
    error: function (x, t, e) {
        if (this.statusCode[x.status] == undefined) {
            console.debug(t + '：' + e);
            alert('请求发生错误，请稍后再试！');
        }
    },
    statusCode: {
        0: function () {
            alert('请求超时,服务器未响应！')
        },
        401: function () {
            $('.login').dialog('open');
        },
        403: function () {
            alert('权限不足，您暂不允许此操作！');
        },
        408: function () {
            alert('请求超时！\n您的网络可能已经中断！');
        },
        404: function () {
            alert('对不起，您当前请求不存在！')
        },
        500: function () {
            alert('请求失败，服务器内部发生错误！');
        },
        503: function () {
            alert('服务器繁忙，请稍后再试！');
        }
    }
});
var ajaxevent = null;
$(document).ready(function (e) {
    if (!checkVersion())
        return;
    checkClient();
    $('body').prepend('<div class="loading" id="loading"></div>');
    $("#loading").dialog({
        autoOpen: false,
        modal: true,
        dialogClass: 'dialogloading',
        resizable: false,
        //closeOnEscape:false,
        close: function (event, ui) {
            if (event.which == 27) {
                if (ajaxevent != null) {
                    ajaxevent.abort();
                    ajaxevent = null
                }
            }
        }
    });
    longController.initControl();
});
function showtime(obj) {
    var d = new Date();
    var week = ['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日'];
    var timestr = '';//d.toLocaleDateString()+' '+week[d.getDay()];
    timestr += d.getFullYear() + '年';
    timestr += d.getMonth() + 1 + '月';
    timestr += d.getDate() + '日';
    timestr += ' ' + d.getHours();
    timestr += ':' + d.getMinutes();
    timestr += ':' + d.getSeconds();
    timestr += ' ' + week[d.getDay()];
    $(obj).text(timestr);
}
function md5(str) {
    var hex_chr = "0123456789abcdef";

    function rhex(num) {
        str = "";
        for (var j = 0; j <= 3; j++)
            str += hex_chr.charAt((num >> (j * 8 + 4)) & 0x0F)
                + hex_chr.charAt((num >> (j * 8)) & 0x0F);
        return str;
    }

    function str2blks_MD5(str) {
        nblk = ((str.length + 8) >> 6) + 1;
        blks = new Array(nblk * 16);
        var i;
        for (i = 0; i < nblk * 16; i++)
            blks[i] = 0;
        for (i = 0; i < str.length; i++)
            blks[i >> 2] |= str.charCodeAt(i) << ((i % 4) * 8);
        blks[i >> 2] |= 0x80 << ((i % 4) * 8);
        blks[nblk * 16 - 2] = str.length * 8;
        return blks;
    }

    function add(x, y) {
        var lsw = (x & 0xFFFF) + (y & 0xFFFF);
        var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
        return (msw << 16) | (lsw & 0xFFFF);
    }

    function rol(num, cnt) {
        return (num << cnt) | (num >>> (32 - cnt));
    }

    function cmn(q, a, b, x, s, t) {
        return add(rol(add(add(a, q), add(x, t)), s), b);
    }

    function ff(a, b, c, d, x, s, t) {
        return cmn((b & c) | ((~b) & d), a, b, x, s, t);
    }

    function gg(a, b, c, d, x, s, t) {
        return cmn((b & d) | (c & (~d)), a, b, x, s, t);
    }

    function hh(a, b, c, d, x, s, t) {
        return cmn(b ^ c ^ d, a, b, x, s, t);
    }

    function ii(a, b, c, d, x, s, t) {
        return cmn(c ^ (b | (~d)), a, b, x, s, t);
    }

    function MD5(str) {
        x = str2blks_MD5(str);
        var a = 1732584193;
        var b = -271733879;
        var c = -1732584194;
        var d = 271733878;
        for (var i = 0; i < x.length; i += 16) {
            var olda = a;
            var oldb = b;
            var oldc = c;
            var oldd = d;
            a = ff(a, b, c, d, x[i + 0], 7, -680876936);
            d = ff(d, a, b, c, x[i + 1], 12, -389564586);
            c = ff(c, d, a, b, x[i + 2], 17, 606105819);
            b = ff(b, c, d, a, x[i + 3], 22, -1044525330);
            a = ff(a, b, c, d, x[i + 4], 7, -176418897);
            d = ff(d, a, b, c, x[i + 5], 12, 1200080426);
            c = ff(c, d, a, b, x[i + 6], 17, -1473231341);
            b = ff(b, c, d, a, x[i + 7], 22, -45705983);
            a = ff(a, b, c, d, x[i + 8], 7, 1770035416);
            d = ff(d, a, b, c, x[i + 9], 12, -1958414417);
            c = ff(c, d, a, b, x[i + 10], 17, -42063);
            b = ff(b, c, d, a, x[i + 11], 22, -1990404162);
            a = ff(a, b, c, d, x[i + 12], 7, 1804603682);
            d = ff(d, a, b, c, x[i + 13], 12, -40341101);
            c = ff(c, d, a, b, x[i + 14], 17, -1502002290);
            b = ff(b, c, d, a, x[i + 15], 22, 1236535329);
            a = gg(a, b, c, d, x[i + 1], 5, -165796510);
            d = gg(d, a, b, c, x[i + 6], 9, -1069501632);
            c = gg(c, d, a, b, x[i + 11], 14, 643717713);
            b = gg(b, c, d, a, x[i + 0], 20, -373897302);
            a = gg(a, b, c, d, x[i + 5], 5, -701558691);
            d = gg(d, a, b, c, x[i + 10], 9, 38016083);
            c = gg(c, d, a, b, x[i + 15], 14, -660478335);
            b = gg(b, c, d, a, x[i + 4], 20, -405537848);
            a = gg(a, b, c, d, x[i + 9], 5, 568446438);
            d = gg(d, a, b, c, x[i + 14], 9, -1019803690);
            c = gg(c, d, a, b, x[i + 3], 14, -187363961);
            b = gg(b, c, d, a, x[i + 8], 20, 1163531501);
            a = gg(a, b, c, d, x[i + 13], 5, -1444681467);
            d = gg(d, a, b, c, x[i + 2], 9, -51403784);
            c = gg(c, d, a, b, x[i + 7], 14, 1735328473);
            b = gg(b, c, d, a, x[i + 12], 20, -1926607734);
            a = hh(a, b, c, d, x[i + 5], 4, -378558);
            d = hh(d, a, b, c, x[i + 8], 11, -2022574463);
            c = hh(c, d, a, b, x[i + 11], 16, 1839030562);
            b = hh(b, c, d, a, x[i + 14], 23, -35309556);
            a = hh(a, b, c, d, x[i + 1], 4, -1530992060);
            d = hh(d, a, b, c, x[i + 4], 11, 1272893353);
            c = hh(c, d, a, b, x[i + 7], 16, -155497632);
            b = hh(b, c, d, a, x[i + 10], 23, -1094730640);
            a = hh(a, b, c, d, x[i + 13], 4, 681279174);
            d = hh(d, a, b, c, x[i + 0], 11, -358537222);
            c = hh(c, d, a, b, x[i + 3], 16, -722521979);
            b = hh(b, c, d, a, x[i + 6], 23, 76029189);
            a = hh(a, b, c, d, x[i + 9], 4, -640364487);
            d = hh(d, a, b, c, x[i + 12], 11, -421815835);
            c = hh(c, d, a, b, x[i + 15], 16, 530742520);
            b = hh(b, c, d, a, x[i + 2], 23, -995338651);
            a = ii(a, b, c, d, x[i + 0], 6, -198630844);
            d = ii(d, a, b, c, x[i + 7], 10, 1126891415);
            c = ii(c, d, a, b, x[i + 14], 15, -1416354905);
            b = ii(b, c, d, a, x[i + 5], 21, -57434055);
            a = ii(a, b, c, d, x[i + 12], 6, 1700485571);
            d = ii(d, a, b, c, x[i + 3], 10, -1894986606);
            c = ii(c, d, a, b, x[i + 10], 15, -1051523);
            b = ii(b, c, d, a, x[i + 1], 21, -2054922799);
            a = ii(a, b, c, d, x[i + 8], 6, 1873313359);
            d = ii(d, a, b, c, x[i + 15], 10, -30611744);
            c = ii(c, d, a, b, x[i + 6], 15, -1560198380);
            b = ii(b, c, d, a, x[i + 13], 21, 1309151649);
            a = ii(a, b, c, d, x[i + 4], 6, -145523070);
            d = ii(d, a, b, c, x[i + 11], 10, -1120210379);
            c = ii(c, d, a, b, x[i + 2], 15, 718787259);
            b = ii(b, c, d, a, x[i + 9], 21, -343485551);
            a = add(a, olda);
            b = add(b, oldb);
            c = add(c, oldc);
            d = add(d, oldd);
        }
        return rhex(a) + rhex(b) + rhex(c) + rhex(d);
    }

    return MD5(str);
}